package com.rocky.project.util;

import java.io.IOException;
import java.io.Writer;
import java.util.Locale;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.webwork.views.freemarker.FreemarkerManager;
import com.opensymphony.webwork.views.util.ResourceUtil;
import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.xwork.LocaleProvider;
import com.opensymphony.xwork.util.OgnlValueStack;

import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

public class FreemarkerUtil {
	private String pContentType = "text/json";	
	private ActionInvocation invocation;
	private static Configuration configuration;
	private static ObjectWrapper wrapper;	
	private static FreemarkerUtil instance = null;

    public final static synchronized FreemarkerUtil getInstance() {
        // if the instance creation failed, make sure there is a default instance
        if (instance == null) {
            instance = new FreemarkerUtil();
        }
        return instance;
    }
	public void setContentType(String aContentType) {
		pContentType = aContentType;
	}

	public String getContentType() {
		return pContentType;
	}

	public String doExecute(String location, ActionInvocation invocation) throws IOException, TemplateException {
		this.invocation = invocation;
		configuration = getConfiguration();
		wrapper = getObjectWrapper();
		if (!location.startsWith("/")) {
			ActionContext ctx = invocation.getInvocationContext();
			HttpServletRequest req = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
			String base = ResourceUtil.getResourceBase(req);
			location = base + "/" + location;
		}
		Template template = configuration.getTemplate(location, deduceLocale());
		TemplateModel model = createModel();
		try {
			Writer writer = new java.io.StringWriter();
			template.process(model, writer);			
			return writer.toString();
		} finally {
			postTemplateProcess(template, model);
		}
	}

	/**
	 * This method is called from {@link #doExecute(String, ActionInvocation)}
	 * to obtain the FreeMarker configuration object that this result will use
	 * for template loading. This is a hook that allows you to custom-configure
	 * the configuration object in a subclass, or to fetch it from an IoC
	 * container. <p/> <b> The default implementation obtains the configuration
	 * from the ConfigurationManager instance. </b>
	 */
	private static Configuration getConfiguration() throws TemplateException {
		return FreemarkerManager.getInstance().getConfiguration(ServletActionContext.getServletContext());
	}
	/**
	 * This method is called from {@link #doExecute(String, ActionInvocation)}  to obtain the
	 * FreeMarker object wrapper object that this result will use for adapting objects into template
	 * models. This is a hook that allows you to custom-configure the wrapper object in a subclass.
	 * <p/>
	 * <b>
	 * The default implementation returns {@link Configuration#getObjectWrapper()}
	 * </b>
	 */
	private static ObjectWrapper getObjectWrapper() {
		return configuration.getObjectWrapper();
	}
	/**
	 * Build the instance of the ScopesHashModel, including JspTagLib support
	 * <p/>
	 * Objects added to the model are
	 * <p/>
	 * <ul>
	 * <li>Application - servlet context attributes hash model
	 * <li>JspTaglibs - jsp tag lib factory model
	 * <li>Request - request attributes hash model
	 * <li>Session - session attributes hash model
	 * <li>req - the HttpServletRequst object for direct access
	 * <li>res - the HttpServletResponse object for direct access
	 * <li>stack - the OgnLValueStack instance for direct access
	 * <li>ognl - the instance of the OgnlTool
	 * <li>action - the action itself
	 * <li>exception - optional : the JSP or Servlet exception as per the servlet spec (for JSP Exception pages)
	 * <li>webwork - instance of the WebWorkUtil class
	 * </ul>
	 */
	private TemplateModel createModel() throws TemplateModelException {
		ServletContext servletContext = ServletActionContext.getServletContext();
		HttpServletRequest request = ServletActionContext.getRequest();
		HttpServletResponse response = ServletActionContext.getResponse();
		OgnlValueStack stack = ServletActionContext.getContext().getValueStack();
		Object action = null;
		if (invocation != null){
			action = invocation.getAction(); //Added for NullPointException	
		}
		return FreemarkerManager.getInstance().buildTemplateModel(stack, action, servletContext, request, response, wrapper);
	}
	/**
	 * Returns the locale used for the {@link Configuration#getTemplate(String, Locale)} call. The base implementation
	 * simply returns the locale setting of the action (assuming the action implements {@link LocaleProvider}) or, if
	 * the action does not the configuration's locale is returned. Override this method to provide different behaviour,
	 */
	private Locale deduceLocale() {
		if (invocation.getAction() instanceof LocaleProvider) {
			return ((LocaleProvider) invocation.getAction()).getLocale();
		} else {
			return configuration.getLocale();
		}
	}
	/**
	 * the default implementation of postTemplateProcess applies the contentType parameter
	 */
	protected void postTemplateProcess(Template template, TemplateModel data) throws IOException {
	}

}
